
#include "app_cmd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "stm32f10x.h"
#include "bsp_uart_fifo.h"
#include "pump.h"
#include "ssz_tick_time.h"
#include "modbus.h"
#include "pwm_motor.h"


/************************************************
* Variables
************************************************/
static char g_app_cmd_receive_str[MAX_SIZE_OF_RECEIVE_STR];
static int g_app_cmd_receive_index = 0;
static bool g_app_cmd_is_enable_cmd = false;
static const AppCmdInfo* g_app_cmd_info_ptr = NULL;
extern int g_out_of_time;

/************************************************
* Functions
************************************************/
//all command functions
static int app_cmd_help(const char* cmd, char* params[], int param_size)
{
    const AppCmdInfo *p = g_app_cmd_info_ptr;		

    printf("all cmds:\n");
    
    while(p->command[0] != 0){     
        printf("%-10s", p->command);
        if (p->description[0] != 0){
            printf(" %s", p->description);
        }
        putchar('\n');
        p++;
    } 	

    return 0;
}

static int app_cmd_exit(const char* cmd, char* params[], int param_size)
{
    //do not receive data
    g_app_cmd_is_enable_cmd = false;

    return 0;
}

static int app_cmd_init_pump(const char* cmd, char* params[], int param_size)
{ 
    if(param_size == 2 && strcmp(params[1],"left") == 0){
        execute_pump_cmd(kPumpInitOutToLeft, 0, atoi(params[0] + 2));
        printf("init output to left\n");
    }else if(param_size == 2 && strcmp(params[1],"right") == 0){
        execute_pump_cmd(kPumpInitOutToRight, 0, atoi(params[0] + 2));
        printf("init output to right\n");
    }else if(param_size == 1) {
        execute_pump_cmd(kPumpInitOutToRight, 0, atoi(params[0] + 2));
        printf("init output to right\n");
    }
   
    return 0;
}

static int app_cmd_move_to(const char* cmd, char* params[], int param_size)
{
    int pos = 0;
    int pump = 0;

    if(param_size == 2){
       pos = atoi(params[1]);
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
    }

    if(pos >=0 && pos <= 6000){
        execute_pump_cmd(kPumpMoveTo, pos, pump);
        printf("to pos:%d\n", pos);
    }
    
    return 0;
}

static int app_cmd_input(const char* cmd, char* params[], int param_size)
{   
    int pump = 0;

    if(param_size == 1){
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
       execute_pump_cmd(kPumpInput, 0, pump);
    }
    printf("input\n");

    return 0;
}

static int app_cmd_output(const char* cmd, char* params[], int param_size)
{   
    int pump = 0;

    if(param_size == 1){
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
       execute_pump_cmd(kPumpOutput, 0, pump);
    }
    printf("output\n");

    return 0;
}

static int app_cmd_stop(const char* cmd, char* params[], int param_size)
{   
    int pump = 0;

    if(param_size == 1){
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
       execute_pump_cmd(kPumpStop, 0, pump);
    }

    printf("stop\n");

    return 0;
}


static int app_cmd_top(const char* cmd, char* params[], int param_size)
{   
    int pump = 0;

    if(param_size == 1){
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
       execute_pump_cmd(kPumpMoveTo, 0, pump);
    }

    printf("top\n");

    return 0;
}

static int app_cmd_bottom(const char* cmd, char* params[], int param_size)
{   
    int pump = 0;

    if(param_size == 1){
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
       execute_pump_cmd(kPumpMoveTo, 6000, pump);
    }
    printf("bottom\n");

    return 0;
}
static int app_cmd_up(const char* cmd, char* params[], int param_size)
{   
    int pos = 0;
    int pump = 0;

    if(param_size == 2){
       pos = atoi(params[1]);
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
    }

    if(pos >=0 && pos <= 6000){
        execute_pump_cmd(kPumpUp, pos, pump);
        printf("up:%d\n", pos);
    }

    return 0;
}

static int app_cmd_down(const char* cmd, char* params[], int param_size)
{   
    int pos = 0;
    int pump = 0;

    if(param_size == 2){
       pos = atoi(params[1]);
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
    }

    if(pos >=0 && pos <= 6000){
        execute_pump_cmd(kPumpDown, pos, pump);
        printf("down:%d\n", pos);
    }

    return 0;
}

static int app_cmd_set_speed(const char* cmd, char* params[], int param_size)
{   
    int pos = 0;
    int pump = 0;

    if(param_size == 2){
       pos = atoi(params[1]);
       pump = atoi(params[0]) + 2; //change to pump ADDR1 or ADDR2
    }


    if(pos >= 5 && pos <= 5000){
        execute_pump_cmd(kPumpSetSpeed, pos, pump);
        printf("set speed:%d\n", pos);
    }

    return 0;
}

static int app_cmd_auto(const char* cmd, char* params[], int param_size)
{   
    int fill_speed, dose_speed, volume, pump;
    
    if(param_size == 4){
       pump = atoi(params[0]) + 2;
       fill_speed = atoi(params[1]);
       dose_speed = atoi(params[2]);
       volume = atoi(params[3]);

       execute_pump_auto( fill_speed, dose_speed, volume, pump);
       printf("set fill_speed:%d dose_speed:%d volume:%d, pump:%d,\n",fill_speed,dose_speed,volume, pump);
    }

    return 0;
}

static int app_cmd_user(const char* cmd, char* params[], int param_size)
{   	
    if(param_size == 2 && strcmp(params[1],"") != 0){
        execute_pump_cmd_str(params[1], atoi(params[0]) + 2);
    }

    printf("execute cmd:%s\n",params[1]);
    return 0;
}

static int app_cmd_run_time(const char* cmd, char* params[], int param_size)
{   	
    printf("run time:%6.2fs\r\n", ssz_tick_time_now() / 1000.0);

    return 0;
}

static int app_cmd_feed_dog(const char* cmd, char* params[], int param_size)
{   	   
    if(param_size == 1){
       g_out_of_time = atoi(params[0]);
    }

    printf("expirted time: %ds\r\n",g_out_of_time);

    return 0;
}

static int app_cmd_clean_count(const char* cmd, char* params[], int param_size)
{   	   
    if(param_size == 2){
       g_pump_manual_para[atoi(params[0]) - 1].clean_times = atoi(params[1]);
    }

    printf("pump %d auto clean time:%d\r\n", atoi(params[0]), g_pump_manual_para[atoi(params[0]) - 1].clean_times);

    return 0;
}

static int app_cmd_feed_count(const char* cmd, char* params[], int param_size)
{   	   
    if(param_size == 2){
       g_pump_manual_para[atoi(params[0]) - 1].feed_times = atoi(params[1]);
    }

    printf("pump %d auto feed time:%d\r\n",  atoi(params[0]), g_pump_manual_para[atoi(params[0]) - 1].feed_times);

    return 0;
}
const char *mode[]={"fill", "prep", "dose", "empty", "clean", "feed"};
static int app_cmd_para_out(const char* cmd, char* params[], int param_size)
{   	   
    int pump;
    if(param_size == 1){
        pump = atoi(params[0]) - 1;

        printf("pump %d auto fill speed: %dml/min\r\n", atoi(params[0]), g_pump_manual_para[pump].fill_speed / 1000);
        printf("pump %d auto volume: %dml\r\n", atoi(params[0]), g_pump_manual_para[pump].volume / 1000);
        printf("pump %d auto dose speed: %dml/min\r\n", atoi(params[0]), g_pump_manual_para[pump].dose_speed / 1000);
        printf("pump %d manual dose: %dml\r\n", atoi(params[0]), g_pump_manual_para[pump].manual_dosing / 1000);
        printf("pump %d manual fill: %dml\r\n", atoi(params[0]), g_pump_manual_para[pump].manual_filling / 1000);
        printf("pump %d mode: %s\r\n", atoi(params[0]), mode[g_pump_manual_para[pump].mode - 1]);
        printf("pump %d clean times: %d\r\n", atoi(params[0]), g_pump_manual_para[pump].clean_times);
        printf("pump %d feed times: %d\r\n\n", atoi(params[0]), g_pump_manual_para[pump].feed_times);
    }
    return 0;
}

static int app_cmd_set_motor_dir(const char* cmd, char* params[], int param_size)
{   	   
    if(param_size == 2){
       if(atoi(params[0]) == kMotorOne)
           motor_direction(kMotorOne, atoi(params[1]));
       else
           motor_direction(kMotorTwo, atoi(params[1]));
    }

    return 0;
}

static int app_cmd_set_motor_duty(const char* cmd, char* params[], int param_size)
{   	   
    uint16_t duty = 200;

    if(param_size == 2){
       if (atoi(params[0]) == kMotorOne){
            duty = atoi(params[1]);
            pwm_set_duty(kMotorOne, duty);
       } else {
            duty = atoi(params[1]);
            pwm_set_duty(kMotorTwo, duty);
       }
    }
    
    return 0; 
}
static int app_cmd_set_motor_disable(const char* cmd, char* params[], int param_size)
{   	   
    if(param_size == 1){
       if (atoi(params[0]) == kMotorOne){
            pwm_out_disable(kMotorOne);
       } else {
            pwm_out_disable(kMotorTwo);
       }
    }

    return 0;
}

static int app_cmd_set_motor_enable(const char* cmd, char* params[], int param_size)
{   	   
    //pwm_init();

    //pwm_out_enable(kMotorOne);
    if(param_size == 1){
       if (atoi(params[0]) == kMotorOne){
            pwm_out_enable(kMotorOne);
       } else {
            pwm_out_enable(kMotorTwo);
       }
    }

    return 0;
}


//all cmd infos
static const AppCmdInfo g_app_cmd_info[] =
{	
    {"init", app_cmd_init_pump, "init pump to left or right"}, 
    {"input", app_cmd_input, "valve to input"},
    {"output", app_cmd_output, "valve to output"},
    {"stop", app_cmd_stop, "stop pump, param1: 1-pump1, 2-pump2"},
    {"move_to", app_cmd_move_to, "to position(0-6000),param1:pump, param2:pos"},
    {"top", app_cmd_top, "move to top"},
    {"bottom", app_cmd_bottom, "move to bottom"},
    {"up", app_cmd_up, "pump up"},
    {"down", app_cmd_down, "pump down"},
    {"set_speed", app_cmd_set_speed, "set speed"},
    {"auto", app_cmd_auto, "auto mode,set fill speed, dose speed, volume"},

    {"user_cmd", app_cmd_user, "execute user input cmd"},
    {"run_time", app_cmd_run_time, "run time since power on"},
    {"feed_dog", app_cmd_feed_dog, "feed watchdog"},
    {"feed_time", app_cmd_feed_count, "auto feed times"},
    {"clean_time", app_cmd_clean_count, "auto clean times"},
    {"para", app_cmd_para_out, "output parameters"},
    {"motor_dir", app_cmd_set_motor_dir, "set motor direction"},
    {"motor_duty", app_cmd_set_motor_duty, "set motor duty"},
    {"motor_disable", app_cmd_set_motor_disable, "motor disable"},
    {"motor_enable", app_cmd_set_motor_enable, "motor enable"},

    {"exit", app_cmd_exit, "exit cmd mode"},
    {"help", app_cmd_help, "for this cmd\n"},

	//below must at end
    {"", NULL}   
};

/***********************************************
* Description:
*   parse all params from the cmd
* Argument:
*   cmd:
*   params:
*
* Return:
*   the params count
************************************************/
static int app_cmd_parse_params(char* cmd, char* params[], int params_max)
{
    int param_index = 0;

    while(cmd != NULL && param_index<params_max){
        //get one param
        params[param_index] = cmd;
        param_index++;

        //find the ' '
        cmd = strchr(cmd, ' ');
        if(cmd != NULL){
            *cmd = 0;
            cmd ++;
        }else{
            break;
        }
    }
    return param_index;
}

/***********************************************
* Description:
*   parse cmd str
* Argument:
*   cmd:
*
* Return:
*
************************************************/
static void app_cmd_parse_cmd(char* cmd)
{          
    if (strcmp(cmd, CMD_ENABLE_PASSWORD)==0){
        printf("cmd mode enable, input 'help' to get a valid cmd\n");
        g_app_cmd_is_enable_cmd = true;
        return;
    }else if(g_app_cmd_is_enable_cmd){ 
        int ret = 0;
        char *params[10];
        int param_size = 0;
        const AppCmdInfo* p;
        char *work_str;

        //find the ' '
        work_str = strchr(cmd, ' ');
        if(work_str != NULL){
            *work_str = 0;
            work_str ++;
        }
        
        param_size = app_cmd_parse_params(work_str, params, 10);
        
        p = g_app_cmd_info_ptr;

        //find the cmd handler
        while(p->command[0] != 0){
            if (strcmp(p->command, cmd)==0){
                ret = p->handler(cmd, params, param_size);
                break;
            }
            p ++;
        }


        //if not find cmd handler, return -1
        if (p->command[0] == 0){
            ret = -1;
            if(g_app_cmd_is_enable_cmd){
                puts("invalid cmd!");
            }
        }else if(ret != 0){
            printf("cmd return error code:%d\n", (int)ret);
        }
    }
}

/***********************************************
* Description:
*   handle char received from UART
* Argument:
*   ch:
*   is_handled_ok_at_pre_handler:
*
* Return:
*
************************************************/
bool app_cmd_on_get_byte(char ch)
{
    //if previous handler handle it OK, reset the index
    if (ch == '\r' || ch=='\n'){//cmd end char|| ch=='\n'
        g_app_cmd_receive_str[g_app_cmd_receive_index] = '\0';
        
        if(g_app_cmd_receive_index>0){
            //parse the cmd
            app_cmd_parse_cmd(g_app_cmd_receive_str);
        }
        //reset the index
        g_app_cmd_receive_index = 0;
    }else{       

        //receive cmd srt
        g_app_cmd_receive_str[g_app_cmd_receive_index] = ch;
		g_app_cmd_receive_index ++;
        
        if(g_app_cmd_receive_index >= MAX_SIZE_OF_RECEIVE_STR - 1)
        {
            g_app_cmd_receive_index = 0;
        }
    }
    return true;
}

/***********************************************
* Description:
*
* Argument:
*
* Return:
*
************************************************/
void app_cmd_init( void )
{
    g_app_cmd_info_ptr = g_app_cmd_info;
    g_app_cmd_is_enable_cmd = true;
}

